package com.youxin.busfoundation.common.es;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.elasticsearch.action.search.SearchPhaseExecutionException;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;

import com.youxin.busfoundation.bean.classify.QueryClassifyBean;
import com.youxin.busfoundation.common.GlobalConfig;
import com.youxin.busfoundation.common.es.bean.CompanyInfoBean;
import com.youxin.busfoundation.common.es.bean.RequestQueryLeadsBean;
import com.youxin.busfoundation.utils.es.EsBasePage;
import com.youxin.foundation.interfaces.Convert;
import com.youxin.foundation.utils.ArrayUtils;
import com.youxin.foundation.utils.JsonUtils;

import feign.Logger;

/**
 * 搜索基础类
 * 
 * @author yingde.cao
 *
 */
public class BaseSearch<T> {
	protected static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(BaseSearch.class);

	protected Convert<T> convert;

	public BaseSearch() {
	}

	public BaseSearch(Convert<T> convert) {
		this.convert = convert;
	}
	
	public static List<String> convertIndustry(List<Object> list)
	{
		if(ArrayUtils.isEmpty(list))
		{
			return new ArrayList<>();
		}
		List<String> indutrys=new ArrayList<>(list.size());
		for(Object obj:list){
			if(obj instanceof Integer)
			{
				indutrys.add(String.valueOf(obj));
			}
		}
		return indutrys;
	}

	/**
	 * 搜索基础方法
	 * 
	 * @param requestLeadsBean
	 * @param modelCls
	 *            模型
	 * @param queryBuilder
	 *            搜索条件
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	protected EsBasePage<Object> queryList(EsBasePage<Object> requestBean, Class<T> modelCls, QueryBuilder queryBuilder,
			SearchStatement searchStatement, String[] indexes, String[] searchTypes) throws Exception {
		Integer pageIndex = requestBean.getPageNo();
		Integer pageSize = requestBean.getPageSize();

		int pageNo = pageIndex != null && pageIndex > 0 ? pageIndex : 1;
		requestBean.setPageNo(pageNo);
		int pageCount = pageSize != null && pageSize > 0 ? pageSize : GlobalConfig.PAGE_SIZE;
		requestBean.setPageSize(pageCount);
		Client client = EsClient.instance().getClient();
		try {
			SearchRequestBuilder srb = client.prepareSearch(indexes);
			srb.setSearchType(SearchType.DFS_QUERY_THEN_FETCH);
			if (searchTypes != null && searchTypes.length > 0) {
				srb.setTypes(searchTypes);
			}
			srb.setFrom((pageNo - 1) * pageSize).setSize(pageSize).setExplain(true);

			// srb.setQuery(queryBuilder);
			// // srb.setFetchSource(includes, excludes)
			// HighlightBuilder hb = new HighlightBuilder();
			// hb.field("full_name").preTags("...").postTags("...");
			// srb.highlighter(hb);
			if (queryBuilder != null) {
				srb.setQuery(queryBuilder);
			}
			if (searchStatement != null) {
				searchStatement.execute(srb);
			}

			SearchResponse response = srb.execute().actionGet(GlobalConfig.ES_SEARCH_TIMEOUT);
			SearchHits hits = response.getHits();
			/**
			 * 设置总数
			 */
			requestBean.setTotalRecord(Math.min(GlobalConfig.ES_SEARCH_MAX_RECORDS, hits.totalHits));
			List<T> list = new ArrayList<>(requestBean.getPageSize());
			for (SearchHit searchHit : hits) {
				
				T bean = null;
				Map<String, HighlightField> highLightFields = searchHit.getHighlightFields();
				if (highLightFields.size() > 0) {
					Map<String, Object> sourceMaps = searchHit.getSource();
					for (String key : highLightFields.keySet()) {
						Text[] fragments = highLightFields.get(key).fragments();
						String name = "";
						for (Text text : fragments) {
							name += text;
						}
						if (name.length() > 0) {
							sourceMaps.put(key, name);
						}
					}
					//sourceMaps=convertSourceMap(sourceMaps);
					//bean = JsonUtils.mapToObject(sourceMaps, modelCls);
					String sourceString=JsonUtils.objectToFasterxmlJsonString(sourceMaps);
					bean = JsonUtils.stringToFasterxmlObject(sourceString, modelCls);
				} else {
					//String sourceString = searchHit.getSourceAsString();
					//bean = JsonUtils.stringToFasterxmlObject(sourceString, modelCls);
					
					Map<String, Object> sourceMaps = searchHit.getSource();
					String sourceString=JsonUtils.objectToFasterxmlJsonString(sourceMaps);
					bean = JsonUtils.stringToFasterxmlObject(sourceString, modelCls);
					//sourceMaps=convertSourceMap(sourceMaps);
					// bean=JsonUtils.mapToObject(sourceMaps,modelCls);					
					if (bean == null) {
						logger.info("error format:" + String.valueOf(searchHit.getSourceAsString()));
					}
				}
				
				if (bean != null) {
					
					if (convert != null) {
						convert.apply(bean);
					}
					list.add(bean);
				}
			}
			requestBean.setResults((List<Object>) (List<?>) list);
		} catch (SearchPhaseExecutionException e) {

		} catch (Exception e) {
			throw e;
		} finally {

		}

		return requestBean;
	}
	
	public static Map<String, Object> convertSourceMap(Map<String, Object> sourceMap)
	{
		Map<String, Object> result=new HashMap<>(sourceMap.size());
		for(String key:sourceMap.keySet())
		{
			result.put(key.replace("_", ""), sourceMap.get(key));
		}
		return result;
	}
	
	

	protected BoolQueryBuilder addClassify(RequestQueryLeadsBean bean) {
		/**
		 * 分类查询
		 */
		BoolQueryBuilder tempQueryBuilder = null;
		if (!ArrayUtils.isEmpty(bean.getIndustry())) {
			if (tempQueryBuilder == null) {
				tempQueryBuilder = new BoolQueryBuilder();
			}
			tempQueryBuilder.should(QueryBuilders.termsQuery("industry", bean.getIndustry()));
		}
		if (!ArrayUtils.isEmpty(bean.getIndustrySmall())) {
			if (tempQueryBuilder == null) {
				tempQueryBuilder = new BoolQueryBuilder();
			}
			tempQueryBuilder.should(QueryBuilders.termsQuery("industry_small", bean.getIndustrySmall()));
		}
		return tempQueryBuilder;

	}

	/**
	 * 查询列表
	 * 
	 * @param modelCls
	 * @param queryBuilder
	 * @param searchStatement
	 * @param indexes
	 * @return
	 * @throws Exception
	 */
	protected List<T> queryList(Class<T> modelCls, QueryBuilder queryBuilder, SearchStatement searchStatement,
			String... indexes) throws Exception {

		Client client = EsClient.instance().getClient();
		try {
			SearchRequestBuilder srb = client.prepareSearch(indexes);
			srb.setSearchType(SearchType.DFS_QUERY_THEN_FETCH);
			//srb.setTypes(GlobalConfig.ES_SLS_COMPANY_INDEX_TYPES);
			srb.setExplain(true);
			// srb.setQuery(queryBuilder);
			// // srb.setFetchSource(includes, excludes)
			// // HighlightBuilder hb = new HighlightBuilder();
			// //
			// hb.field("title").field("detail_text").field("company_name").preTags("...").postTags("...");
			// // srb.highlighter(hb);
			// }

			if (queryBuilder != null) {
				srb.setQuery(queryBuilder);
			}
			if (searchStatement != null) {
				searchStatement.execute(srb);
			}
			SearchResponse response = srb.execute().actionGet(GlobalConfig.ES_SEARCH_TIMEOUT);
			SearchHits hits = response.getHits();
			/**
			 * 设置总数
			 */
			List<T> list = new ArrayList<>();
			for (SearchHit searchHit : hits) {
				//String sourceString = searchHit.getSourceAsString();
				//T bean = JsonUtils.stringToFasterxmlObject(sourceString, modelCls);				
				Map<String, Object> sourceMaps = searchHit.getSource();
				String sourceString=JsonUtils.objectToFasterxmlJsonString(sourceMaps);
				T bean = JsonUtils.stringToFasterxmlObject(sourceString, modelCls);
				
				if (bean != null) {
					if(convert != null){
						convert.apply(bean);
					}
				}else{
					logger.error("资源无法解析::"+String.valueOf(sourceString));
				}
				list.add(bean);
			}
			return list;
		} catch (Exception e) {
			throw e;
		} finally {

		}
	}

	@FunctionalInterface
	public interface SearchStatement {
		public void execute(SearchRequestBuilder srb);
	}

}
